🤖 fix: clear stale usage state when history is rewritten so the next send does not auto-compact - #3818
🤖 fix: clear stale usage state when history is rewritten so the next send does not auto-compact#3818ibetitsmike wants to merge 37 commits into
Conversation
…oundary Start Here (replaceHistory), /reset (resetContext), and /clear (truncateHistory) rewrite history to a fresh context boundary but left the session's in-memory lastUsageState from the previous stream intact. The next sendMessage fed that stale high usage into the on-send compaction check and synthesized a spurious /compact request against the already-cleared context. Clear the session usage state in all three paths; the next send re-seeds accurate usage from post-boundary history. --- _Generated with `mux` • Model: `anthropic:claude-fable-5` • Thinking: `xhigh`_ <!-- mux-attribution: model=anthropic:claude-fable-5 thinking=xhigh -->
Cleanup-gate follow-up: the same stale-usage defect class existed on the heartbeat context reset, exec-subagent hard restart, and edit truncation paths, plus two ordering gaps (destructive replaceHistory cleared history before the summary append could fail, and zero-percentage truncation cleared usage without rewriting anything). Route all context rewrites through clearUsageState() and slim the new tests down to the repo's fake-session wiring pattern. --- _Generated with `mux` • Model: `anthropic:claude-fable-5` • Thinking: `xhigh`_ <!-- mux-attribution: model=anthropic:claude-fable-5 thinking=xhigh -->
|
@codex review |
|
Codex Review: Didn't find any major issues. Nice work! Reviewed commit: ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". |
…st bootstrap CI-only failure on this PR: 35 AgentListItem/GitStatusIndicatorView/ TaskGroupListItem tests failed with "Cannot access 'DragPreviewImage' before initialization". Changing test files shifts bun's CI discovery order, letting a pre-existing order bug surface: files that tear down with `globalThis.document = undefined` poison installDom()'s snapshot/restore, which propagates a document-less environment (with baseline observers present) to later files; @react-dnd/asap then crashes at module eval and leaves react-dnd's internal exports in TDZ, so every later import including `?real=1` re-evals fails. Fix at the chokepoint in tests/ui/dom.ts: the uninstaller re-bootstraps a baseline when it would restore a poisoned document, and react-dnd's module graph is evaluated eagerly while the DOM is healthy so re-evals resolve initialized internals. Both guards in tests/ui/domIsolation.test.ts fail against their own toggle. --- _Generated with `mux` • Model: `anthropic:claude-fable-5` • Thinking: `xhigh`_ <!-- mux-attribution: model=anthropic:claude-fable-5 thinking=xhigh -->
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: e3e6dcd4cf
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
tests/ui/domIsolation.test.ts uses bun:test (it guards bun's single-process module cache behavior), so the Jest-based integration run fails to resolve its import. Skip it via testPathIgnorePatterns like the storybook bun tests. --- _Generated with `mux` • Model: `anthropic:claude-fable-5` • Thinking: `xhigh`_ <!-- mux-attribution: model=anthropic:claude-fable-5 thinking=xhigh -->
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: fadf52b1fc
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
…ider usage Codex P2: for a partial /clear, clearing the in-memory usage cache was ineffective because the retained newest assistant row still carries pre-truncation contextUsage and partial truncation appends no boundary, so seedUsageStateFromHistory() restored the same stale value on the next send. clearUsageState() now also suppresses history seeding until the provider reports fresh usage (updateUsageStateFromModelUsage resets the flag). Guard tests: a baseline proving the boundary-less fixture seeds, and a suppression test that fails without the new guard. --- _Generated with `mux` • Model: `anthropic:claude-fable-5` • Thinking: `xhigh`_ <!-- mux-attribution: model=anthropic:claude-fable-5 thinking=xhigh -->
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 37ced8cace
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Codex P2: tests/ui/domIsolation.test.ts was excluded from Jest but no bun target ran it, so the guards never executed in local validation or CI. Add the file to the Makefile test-unit bun invocation and to the CI Unit job's explicit file list. --- _Generated with `mux` • Model: `anthropic:claude-fable-5` • Thinking: `xhigh`_ <!-- mux-attribution: model=anthropic:claude-fable-5 thinking=xhigh -->
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: acc9f3d7b0
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Codex P2: the in-memory seeding suppression does not survive an app restart. After a partial /clear plus restart, seedUsageStateFromHistory() reloaded the retained assistant row's pre-truncation contextUsage and could spuriously auto-compact again. Sanitize at the source: the partial-truncation rewrite now strips contextUsage and contextProviderMetadata from retained rows, since those snapshots measured a context that no longer exists. Restart-safe with no extra persisted state; the in-memory suppression flag still covers the same-process window until fresh provider usage arrives. Red-green verified via a historyService test. --- _Generated with `mux` • Model: `anthropic:claude-fable-5` • Thinking: `xhigh`_ <!-- mux-attribution: model=anthropic:claude-fable-5 thinking=xhigh -->
|
@codex review |
Codex P2: queued user input rolls back an undispatched heartbeat reset boundary and restores the pre-reset provider context, but the seeding suppression from the boundary append stayed active, so the queued turn could not recover the restored history's near-limit usage and skipped on-send compaction. Re-enable seeding on successful rollback. Guard test drives the real append -> queue -> rollback path and fails without the re-enable. --- _Generated with `mux` • Model: `anthropic:claude-fable-5` • Thinking: `xhigh`_ <!-- mux-attribution: model=anthropic:claude-fable-5 thinking=xhigh -->
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: b25223c6c5
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: f9dd1adc41
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Codex P2: when a partial truncation committed but the monitor-wake restoration step of clearHistoryWithRetiredBashMonitorWakes threw, the invalidation after the wrapper never ran and the session kept its pre-truncation usage. Move the clear into the truncate closure, immediately after the successful rewrite. Guard test injects a wake-restore failure and fails without the move. --- _Generated with `mux` • Model: `anthropic:claude-fable-5` • Thinking: `xhigh`_ <!-- mux-attribution: model=anthropic:claude-fable-5 thinking=xhigh -->
|
@codex review |
Codex P2: message edits truncate a suffix, so the retained prefix's persisted contextUsage still describes the active context. Blanket seeding suppression meant an edit whose stream failed before reporting usage left the next send unable to recover that valid snapshot, bypassing on-send compaction for near-limit prefixes. clearUsageState() gains a preserveHistorySeeding option used by the edit path. Guard test drives edit-then-send and fails without it. --- _Generated with `mux` • Model: `anthropic:claude-fable-5` • Thinking: `xhigh`_ <!-- mux-attribution: model=anthropic:claude-fable-5 thinking=xhigh -->
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: db716c50a6
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: c6704dbd2b
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
…st boundary Codex P2: after a compaction boundary exists, a 25/50/75% truncation can remove only sealed pre-boundary rows, leaving the active provider context unchanged; stripping retained contextUsage and suppressing the in-memory seed then discarded a valid near-limit snapshot and could skip required on-send compaction. truncateHistory now reports whether the cut reached the active window (removed the latest durable boundary or later rows). Rows are sanitized and session usage cleared only in that case. Red-green: forcing the flag true fails the new preserve test; the strip test still guards boundary-less cuts. --- _Generated with `mux` • Model: `anthropic:claude-fable-5` • Thinking: `xhigh`_ <!-- mux-attribution: model=anthropic:claude-fable-5 thinking=xhigh -->
|
@codex review |
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 5d1e3ebd0f
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
…leave renderer ghost rows truncateHistory/clearHistory now take an onRowsDeleted callback fired with each committed step's deleted sequences, even when a later step fails. The three DeleteMessage emitters (truncateHistory, destructive replaceHistory, exec hard-restart clear) emit accumulated committed deletions on failure paths too, so rows already removed from disk cannot linger in the renderer with sequences no retry can report.
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: c9bb86a073
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
…tripping usage while the hazard exists The copied prefix is written with usage snapshots stripped while the archive still exists, so a failed or crashed archive removal leaves nothing stale for a fresh session to seed. Once the removal commits the hazard is gone, and a restore write brings the usage back because it is exact for the restored prefix and an edited near-limit prefix must stay monitored on the next send.
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 170a0d90f0
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
…after the rewrite The edit-truncation commit callback now reports whether the retained rows' persisted usage stays valid. Active-file suffix cuts create no duplicated prefix, so seeding re-enables at commit and a near-limit prefix stays monitored despite the Err; the archived branch keeps suppression until full success.
|
@codex review |
|
Codex Review: Didn't find any major issues. Bravo. Reviewed commit: ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". |
|
@codex review The implementation was substantially simplified after code review. Please review the current head |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: ac9a325823
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
@codex review Addressed the four findings on current head
Please review the current head. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 1db6e95336
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Use target-state hashes to distinguish committed and interrupted archive rewrites, recover legacy tombstones, and serialize logical reads with recovery. Generated with mux • Model: openai:gpt-5.6-sol • Thinking: xhigh <!-- mux-attribution: model=openai:gpt-5.6-sol thinking=xhigh -->
|
@codex review The interrupted archive truncation finding is fixed on |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: f99fc2b4ec
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Let usage rebuilds iterate history through the lock-held path so transaction recovery remains serialized without reacquiring the shared non-reentrant mutex. Generated with mux • Model: openai:gpt-5.6-sol • Thinking: xhigh <!-- mux-attribution: model=openai:gpt-5.6-sol thinking=xhigh -->
|
@codex review The non-reentrant lock finding is fixed on |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 1722f48ab9
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Recover pending archive transactions and capture chat plus sealed history atomically before writing the fork session files. Generated with mux • Model: openai:gpt-5.6-sol • Thinking: xhigh <!-- mux-attribution: model=openai:gpt-5.6-sol thinking=xhigh -->
|
@codex review The fork snapshot race is fixed on |
|
Codex Review: Didn't find any major issues. Chef's kiss. Reviewed commit: ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". |
|
@codex review The latest push fixes the CI failures by keeping manual review refreshes uncached until their loads complete and making the two asynchronous service tests deterministic. |
|
Codex Review: Didn't find any major issues. Breezy! Reviewed commit: ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". |
Summary
Fixes the spurious
/compactturn that occurred after Start Here and other context rewrites. The implementation clears the in-memory usage snapshot at rewrite boundaries and removes stale persisted usage only when a prefix truncation changes the active provider context.Background
AgentSessioncaches the latest context usage for the on-send compaction check. Start Here appended a new compaction boundary without clearing that cache, so the next ordinary message could be replaced by an auto-compaction request based on usage from the old context.The original fix grew to roughly 2,000 net added lines by moving provider policy and renderer callbacks into
HistoryService, adding hidden usage-seeding state, and accumulating recovery and test scaffolding.Implementation
contextUsageandcontextProviderMetadataonly when percentage truncation removes provider-visible rows from the active window.HistoryServicefocused on durable file mutation, without session or renderer callbacks.The final diff is 1,135 additions and 491 deletions, net 644 lines. This is about 69 percent smaller than the original net 2,064-line version while retaining restart and partial-failure safety.
Validation
HistoryService,SessionUsageService,TaskService, andWorkspaceGoalServicesuites.tests/ui/review/refresh.test.ts, 10 tests.make static-check.Risks
Moderate. The cache reset is small and pessimistic. The durable-history changes affect percentage truncation and archived-message edits, with focused coverage for transaction recovery, boundary semantics, sequence counters, and restart-visible metadata. The review refresh change only delays marking a refresh token consumed until its corresponding non-cancelled load succeeds.
Generated with
mux• Model:openai:gpt-5.6-sol• Thinking:xhigh